<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>高级感进度环</title>
    <style>
        * {
            border: 0;
            box-sizing: border-box;
            margin: 0;
            padding: 0
        }

        :root {
            --hue: 223;
            --bg: hsl(var(--hue), 10%, 90%);
            --fg: hsl(var(--hue), 10%, 10%);
            --primary: hsl(var(--hue), 90%, 50%);
            --trans-dur: 0.3s;
            font-size: calc(16px + (32 - 16) * (100vw - 320px) / (2560 - 320))
        }

        body, button {
            font: 1em/1.5 "DM Sans", sans-serif
        }

        body {
            background-color: var(--bg);
            background-image: linear-gradient(145deg, hsla(var(--hue), 10%, 10%, 0), hsla(var(--hue), 10%, 10%, 0.15));
            color: var(--fg);
            display: flex;
            height: 100vh;
            min-height: 23em;
            transition: background-color var(--trans-dur), color var(--trans-dur)
        }

        button {
            background-color: var(--primary);
            border-radius: 0.2em;
            color: hsl(0, 0%, 100%);
            display: block;
            margin: 1.5em auto 0 auto;
            outline: transparent;
            padding: 0.5em 1em;
            transition: background-color 0.15s linear;
            -webkit-tap-highlight-color: transparent;
            cursor: pointer
        }

        button:hover, button:focus-visible {
            background-color: hsl(var(--hue), 90%, 30%)
        }

        main {
            margin: auto
        }

        .loader, .loader__fill, .loader__fill:before, .loader__fill-glow, .loader__middle, .loader__middle:before {
            border-radius: 50%
        }

        .loader {
            --progress: 0;
            --angle: calc(360deg * var(--progress));
            background-color: hsl(var(--hue), 10%, 90%);
            background-image: linear-gradient(145deg, hsla(var(--hue), 10%, 10%, 0.1), hsla(var(--hue), 10%, 10%, 0));
            box-shadow: 0.25em 0.25em 0.5em hsl(var(--hue), 10%, 75%) inset, 0.5em 0.5em 1.5em hsl(var(--hue), 10%, 70%), -0.5em -0.5em 1.5em hsl(var(--hue), 10%, 100%);
            font-family: Play, sans-serif;
            position: relative;
            width: 12em;
            height: 12em;
            transition: background-color var(--trans-dur), box-shadow var(--trans-dur)
        }

        .loader[data-running="true"] + button {
            visibility: hidden
        }

        .loader__fill {
            background-image: conic-gradient(
                    hsl(var(--hue), 90%, 85%), hsl(var(--hue), 90%, calc(85% - 35% * var(--progress))) var(--angle), hsla(var(--hue), 90%, calc(85% - 35% * var(--progress)), 0) var(--angle)
            );
            filter: blur(1px);
            width: 100%;
            height: 100%
        }

        .loader__fill, .loader__fill:before, .loader__fill-glow, .loader__middle, .loader__middle:before, .loader__value {
            position: absolute
        }

        .loader__fill:before, .loader__fill-glow {
            background-image: conic-gradient(
                    hsl(var(--hue), 90%, 90%), hsl(var(--hue), 90%, calc(90% - 40% * var(--progress))) var(--angle), hsla(var(--hue), 90%, calc(90% - 40% * var(--progress)), 0) var(--angle)
            )
        }

        .loader__fill:before {
            content: "";
            display: block;
            inset: 0.25em
        }

        .loader__fill-glow {
            filter: blur(4px);
            opacity: 0.5;
            inset: -0.25em
        }

        .loader__middle, .loader__middle:before {
            transition: background-color var(--trans-dur)
        }

        .loader__middle {
            background-color: hsl(var(--hue), 10%, 100%);
            background-image: linear-gradient(145deg, hsla(var(--hue), 10%, 10%, 0), hsla(var(--hue), 10%, 10%, 0.7));
            box-shadow: 0.5em 0.5em 1em hsla(var(--hue), 10%, 10%, 0.5);
            inset: 1.5em;
            z-index: 1
        }

        .loader__middle:before {
            background-color: hsl(var(--hue), 10%, 90%);
            background-image: linear-gradient(145deg, hsla(var(--hue), 10%, 10%, 0.1), hsla(var(--hue), 10%, 10%, 0));
            content: "";
            display: block;
            inset: 0.25em
        }

        .loader__value {
            font-size: 2.5em;
            display: flex;
            justify-content: center;
            align-items: center;
            inset: 0;
            text-shadow: 0 0.25rem 0.25rem hsla(var(--hue), 10%, 50%, 0.4);
            transition: text-shadow var(--trans-dur)
        }

        @media (prefers-color-scheme: dark) {
            :root {
                --bg: hsl(var(--hue), 10%, 30%);
                --fg: hsl(var(--hue), 10%, 90%)
            }

            .loader {
                background-color: hsl(var(--hue), 10%, 30%);
                box-shadow: 0.25em 0.25em 0.5em hsl(var(--hue), 10%, 15%) inset, 0.5em 0.5em 1.5em hsl(var(--hue), 10%, 20%), -0.5em -0.5em 1.5em hsl(var(--hue), 10%, 40%)
            }

            .loader__middle {
                background-color: hsl(var(--hue), 10%, 40%)
            }

            .loader__middle:before {
                background-color: hsl(var(--hue), 10%, 30%)
            }

            .loader__value {
                text-shadow: 0 0.25rem 0.25rem hsla(var(--hue), 10%, 0%, 0.4)
            }
        }
    </style>
</head>

<body>
<main>
    <div class="loader" data-running="true">
        <div class="loader__fill-glow"></div>
        <div class="loader__fill"></div>
        <div class="loader__middle">
            <div class="loader__value">
                <div data-value>0%</div>
            </div>
        </div>
    </div>
    <button type="button">Replay</button>
</main>
</body>
<script>
    window.addEventListener("DOMContentLoaded", () => {
        const l = new Loader(".loader");
        document.querySelector("button")?.addEventListener("click", l.init.bind(l))
    });

    class Loader {
        progress = 0;
        progressLoop = null;

        constructor(el) {
            this.el = document.querySelector(el);
            this.init()
        }

        init() {
            this.progress = 0;
            this.updateDisplay();
            clearTimeout(this.progressLoop);
            this.progressLoop = setTimeout(this.progressInc.bind(this), 600)
        }

        progressInc() {
            this.progress += 0.01;
            this.progress = +this.progress.toFixed(2);
            this.updateDisplay();
            clearTimeout(this.progressLoop);
            if (this.progress < 1) {
                const interval = 20;
                this.progressLoop = setTimeout(this.progressInc.bind(this), interval)
            }
        }

        updateDisplay() {
            this.el.setAttribute("data-running", this.progress < 1);
            const value = this.el?.querySelector("[data-value]");
            if (value) value.innerText = `${Math.round(this.progress * 100)}%`;
            this.el.style.setProperty("--progress", this.progress)
        }
    }
</script>
</html>